#include "conversemanager.h"
#include "converseabstractconversation.h"

#include "converseprivateconversation.h"
#include "conversegroupconversation.h"
#include "account/accountmember.h"
#include "account/accountbuddy.h"
#include "network/networkmanager.h"
#include "converseabstractmessage.h"
#include "appchat/accountmanager.h"
#include "contact/contactabstractcontact.h"
#include "contact/contactprivatecontact.h"
#include "contact/contactgroupcontact.h"

#include "service/eventservice.h"

#include "appchat/profilemanager.h"
#include "appchat/sqlite/messagetable.h"
#include "appchat/sqlite/messageunsenttable.h"
#include "appchat/sqlite/conversationtable.h"


#include <QDebug>


namespace Converse {

Manager *Manager::m_instance = NULL;

Manager *Manager::instance(QObject *parent)
{
    if (m_instance == NULL)
        m_instance = new Manager(parent);
    return m_instance;
}


Manager::Manager(QObject *parent) :
    QObject(parent)
{
    init();
}


void Manager::init()
{
    // Initialize Event Service
    Service::EventService::instance(this);
    setConnection();
}


void Manager::setConnection() const
{

}


PrivateConversation *
Manager::createPrivateConversation(qint64 id, Contact::PrivateContact *contact)
{
    return new PrivateConversation(id, contact, this);
}


GroupConversation *
Manager::createGroupConversation(qint64 id, Contact::GroupContact *contact)
{
    return new GroupConversation(id, contact, this);
}


AbstractConversation *
Manager::findPrivateConversationById(qint64 id)
{
    Finder::Iterator iterator = m_privateConversationFinder.find(id);
    if (iterator == m_privateConversationFinder.end())
        return NULL;

    return *iterator;
}


AbstractConversation *
Manager::findBySending(qint64 id)
{
    foreach (AbstractConversation *conversation, m_conversationList) {
        if (conversation->hasSending(id) )
            return conversation;
    }
    return NULL;
}


PrivateConversation *
Manager::findPrivateConversationByPartnerId(qint64 id)
{
    AbstractConversation *abstractConversation = m_privateConversationByContactFinder.value(id, NULL);
    if (abstractConversation == NULL)
        return NULL;

    return qobject_cast<PrivateConversation *>(abstractConversation);
}

GroupConversation *
Manager::findGroupConversationByPartnerId(qint64 id)
{
    AbstractConversation *abstractConversation = m_groupConversationByContactFinder.value(id, NULL);
    if (abstractConversation == NULL)
        return NULL;

    return qobject_cast<GroupConversation *>(abstractConversation);
}



GroupConversation *
Manager::findGroupConversationById(qint64 id)
{
    Finder::Iterator iterator = m_groupConversationFinder.find(id);
    if (iterator == m_groupConversationFinder.end())
        return NULL;

    GroupConversation *groupConversation = dynamic_cast<GroupConversation *>(*iterator);
    return groupConversation;
}


PrivateConversation *
Manager::appendPrivateConversation(qint64 id, Contact::PrivateContact *contact)
{
    if (contact == NULL)
        return NULL;

    if (containsPrivateConversation(id))
        return NULL;

    PrivateConversation *conversation = createPrivateConversation(id, contact);
    m_conversationList.append(conversation);
    m_privateConversationFinder.insert(id, conversation);
    m_privateConversationByContactFinder.insert(contact->id(), conversation);
    return conversation;
}


GroupConversation *
Manager::appendGroupConversation(qint64 id, Contact::GroupContact *contact)
{
    if (contact == NULL)
        return NULL;

    if (containsGroupConversation(id))
        return NULL;

    GroupConversation *conversation = createGroupConversation(id, contact);
    m_conversationList.append(conversation);
    m_groupConversationFinder.insert(id, conversation);
    m_groupConversationByContactFinder.insert(contact->id(), conversation);
    return conversation;
}


int Manager::count() const
{
    return m_conversationList.count();
}


int Manager::size() const
{
    return m_conversationList.size();
}


bool Manager::containsPrivateConversation(qint64 id)
{
    return m_privateConversationFinder.contains(id);
}


bool Manager::containsGroupConversation(qint64 id)
{
    return m_groupConversationFinder.contains(id);
}


bool Manager::contains(AbstractConversation *conversation)
{
    if (conversation == NULL)
        return false;

    return m_conversationList.contains(conversation);
}


bool Manager::changePrivateConversationId(AbstractConversation *conversation, qint64 id)
{
    qDebug() << "id change: "<< id << " conversation ID old : "<< conversation->id();
    qint64 conversationId = conversation->id();
    Finder::Iterator iterator = m_privateConversationFinder.find(conversationId);
    if (iterator == m_privateConversationFinder.end())
        return false;

    if (*iterator != conversation)
        return false;

    m_privateConversationFinder.remove(conversationId);
    conversation->setId(id);
    m_privateConversationFinder.insert(id, conversation);

    Sqlite::ConversationTable::insertOrUpdateConversation(conversation);

    return true;
}

void Manager::onMessageReadFromLocal(AbstractMessage *message)
{
    emit messageReadFromLocal(message);
}

void Manager::onMessageReceived(AbstractMessage *message)
{
    emit messageReceived(message);

    Sqlite::MessageTable::insertMessage(message);
    ProfileManager::instance()->updateFriendProfile(message);
}

void Manager::onMessageSent(AbstractMessage *message)
{
    emit messageSent(message);

    ProfileManager::instance()->updateFriendProfile(message);

    Sqlite::MessageTable::insertMessage(message);
    Sqlite::MessageUnsentTable::deleteMessage(message);

}

void Manager::onMessageSend(AbstractMessage *message)
{
    emit messageSend(message);

    Sqlite::MessageUnsentTable::insertMessage(message);
}

void Manager::onDataInserted(int index, MessageGroup *messageGroup)
{
    emit dataInserted(index, messageGroup);
}


//-------------------------------- CLEAR DATA ----------------------------------------
void Manager::clearConversationFinder()
{
    clearPrivateConversationFinder();
    clearGroupConversationFinder();
}


void Manager::clearPrivateConversationFinder()
{
    m_privateConversationFinder.clear();
    m_privateConversationByContactFinder.clear();
}


void Manager::clearGroupConversationFinder()
{
    m_groupConversationFinder.clear();
    m_groupConversationByContactFinder.clear();
}


void Manager::deleteConversationList()
{
    qDeleteAll(m_conversationList);
    m_conversationList.clear();
}


void Manager::clearData()
{
    clearConversationFinder();
    deleteConversationList();
    emit dataCleared();
}

} // namespace converse
